package cn.com.cym.gamezao.service.recruit.impl;

import cn.com.cym.gamezao.base.*;
import cn.com.cym.gamezao.entity.authorize.User;
import cn.com.cym.gamezao.entity.recruit.Job;
import cn.com.cym.gamezao.entity.xmu.recruit.UserApply;
import cn.com.cym.gamezao.enums.ApplyStatus;
import cn.com.cym.gamezao.exception.BaseException;
import cn.com.cym.gamezao.jwt.RequestUser;
import cn.com.cym.gamezao.repository.xmu.recruit.ApplyLogRepository;
import cn.com.cym.gamezao.repository.xmu.recruit.UserApplyRepository;
import cn.com.cym.gamezao.service.recruit.UserApplyService;
import cn.com.cym.gamezao.util.CommonUtils;
import cn.hutool.core.util.ReflectUtil;
import lombok.SneakyThrows;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional(rollbackFor = Exception.class)
public class UserApplyImpl extends BaseImpl<UserApply> implements UserApplyService {

    final EntityManager entityManager;

    final UserApplyRepository thisRepository;

    final ApplyLogRepository applyLogRepository;

    UserApplyImpl(UserApplyRepository thisRepository,ApplyLogRepository applyLogRepository,EntityManager entityManager){
        this.thisRepository = thisRepository;
        this.applyLogRepository = applyLogRepository;
        this.entityManager = entityManager;
    }


    @Override
    public BaseRepository<UserApply, Long> getJpaRepository() {
        return thisRepository;
    }

    /**
     * 控制输入只有创建时间开始结束和 状态
     * @param searchPage pageRequest
     * @return
     */
    @Override
    public Page<UserApply> findByPageable(SearchPage searchPage) {

        String[] sortBy = searchPage.getSortBy().toArray(new String[searchPage.getSortBy().size()]);

        Pageable pageable = PageRequest.of(searchPage.getCurrent()-1, searchPage.getPageSize(), searchPage.getSort(), sortBy);

        Specification<UserApply> specification = new Specification<>() {

            private static final long serialVersionUID = -2661077778894635593L;

            /**
             * @param root: 代表查询的实体类.
             * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
             * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.
             * @param  cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
             * @return  Predicate 类型, 代表一个查询条件.
             */
            @SneakyThrows
            @Override
            public Predicate toPredicate(Root<UserApply> root,
                                         CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Map<String, Field> fieldMap = ReflectUtil.getFieldMap(UserApply.class);

                List<ConditionItem> items = searchPage.getItems();

                //用于查询的条件
                List<Predicate> predicates=new ArrayList<>();

                if(items==null){
                    items=new ArrayList<>();
                }
                for(ConditionItem item:items){
                    //判断是否包含,不包含抛弃
                    if(fieldMap.containsKey(item.getName())){
                        //为空时不做处理
                        if(CommonUtils.isNotEmpty(item.getValue())){
                            //判断
                            if(">=".equals(item.getSign()) ){
                                Predicate predicate = cb.ge(root.get(item.getName()), NumberFormat.getInstance().parse(item.getValue()));
                                predicates.add(predicate);
                            }else if("<=".equals(item.getSign())){
                                Predicate predicate = cb.le(root.get(item.getName()), NumberFormat.getInstance().parse(item.getValue()));
                                predicates.add(predicate);
                            }else if("like".equals(item.getSign())){
                                Predicate predicate = cb.like(root.get(item.getName()), "%"+item.getValue()+"%");
                                predicates.add(predicate);
                            }else if("==".equals(item.getSign())){
                                System.out.println(root.get(item.getName()).getJavaType());
                                Predicate predicate = null;
                                //如果对象是ApplyStatus
                                //System.out.println(root.get(item.getName()).getJavaType().getName());
                                if (root.get(item.getName()).getJavaType().getName().equals("cn.com.cym.gamezao.enums.ApplyStatus")) {
                                    predicate = cb.equal(root.get(item.getName()), ApplyStatus.fromSign(item.getValue()));
                                }else
                                    predicate = cb.equal(root.get(item.getName()), item.getValue());
                                predicates.add(predicate);
                            }

                        }
                    }
                    //处理同字段需要比较大小的
                    else if(item.getItemType().name().equalsIgnoreCase("DATE") && (item.getName().endsWith("1") || item.getName().endsWith("2"))){
                        String itemName = item.getName().substring(0, item.getName().length() - 1);
                        if(fieldMap.containsKey(itemName) && CommonUtils.isNotEmpty(item.getValue())){
                            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                            if(fieldMap.get(itemName).getType().equals(LocalDateTime.class)){
                                LocalDateTime parse = item.getDateValue().atStartOfDay();
                                LocalDateTime localDateTime = parse.plusDays(1);
                                if(">=".equals(item.getSign()) ){
                                    predicates.add(cb.greaterThanOrEqualTo(root.get(itemName), localDateTime));
                                }else if("<=".equals(item.getSign())){
                                    predicates.add(cb.lessThanOrEqualTo(root.get(itemName),localDateTime));
                                }
                            }else {
                                // 先控制在10位数 日期
                                System.out.println(item.getValue());
                                //LocalDate parse = LocalDate.parse(item.getValue().substring(0, 10), df);
                                LocalDate dateValue = item.getDateValue().plusDays(1);
                                if(">=".equals(item.getSign()) ){
                                    predicates.add(cb.greaterThanOrEqualTo(root.get(itemName), dateValue));
                                }else if("<=".equals(item.getSign())){
                                    // + 1
                                    predicates.add(cb.lessThanOrEqualTo(root.get(itemName), dateValue));
                                }
                            }
                        }
                    }
                }
                //判断数据是否已经逻辑删除，已删除数据不显示在前端
                Predicate predicate = cb.equal(root.get("deleted"), false);
                predicates.add(predicate);
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return this.thisRepository.findAll(specification, pageable);
    }

    @Override
    public UserApply findByJobAndUser(Job job, User user) {
        return this.thisRepository.findByJobAndUser(job, user);
    }

    @Override
    public Page ownPage(SearchPage searchPage) {
        User user = RequestUser.get();
        String[] sortBy = searchPage.getSortBy().toArray(new String[searchPage.getSortBy().size()]);

        Pageable pageable = PageRequest.of(searchPage.getCurrent()-1, searchPage.getPageSize(), searchPage.getSort(), sortBy);
        if(searchPage.getItems().size()>0 && CommonUtils.isNotEmpty(searchPage.getItems().get(0).getValue())){
            ApplyStatus applyStatus = ApplyStatus.fromSign(searchPage.getItems().get(0).getValue());
            return this.thisRepository.findAllByUserAndApplyStatus(pageable,user,applyStatus);
        } else {
           return this.thisRepository.findAllByUser(pageable,user) ;
        }
    }
}
